package com.mercycrazy.recruit.advice;

import com.mercycrazy.recruit.annotation.IgnoreResponseAdvice;
import com.mercycrazy.recruit.enums.StatusCode;
import com.mercycrazy.recruit.vo.ApiResponse;
import lombok.SneakyThrows;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

/**
 * 实现统一响应, 编程友好性设计, 自动包装返回对象
 *
 * @author <a href="mailto:1443424326@qq.com">mercycrazy</a>
 * @since 2023-01-08
 */
@SuppressWarnings("all")
@RestControllerAdvice(value = "com.mercycrazy.recruit")
public class ApiResponseDataAdvice implements ResponseBodyAdvice<Object> {

    private final MappingJackson2HttpMessageConverter converter
            = new MappingJackson2HttpMessageConverter();

    /**
     * <h2>判断是否需要对响应进行处理</h2>
     */
    @Override
    @SuppressWarnings("all")
    public boolean supports(MethodParameter returnType,
                            Class<? extends HttpMessageConverter<?>> aClass) {


        if((AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class)
                || returnType.hasMethodAnnotation(ResponseBody.class))
                && !ApiResponse.class.equals(returnType.getParameterType())) {

            if (returnType.getDeclaringClass()
                    .isAnnotationPresent(IgnoreResponseAdvice.class)
                    || returnType.getMethod()
                    .isAnnotationPresent(IgnoreResponseAdvice.class)
            ) {
                return false;
            }

            return true;
        }

        return false;
    }

    @SneakyThrows
    @Override
    @SuppressWarnings("all")
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter,
                                  MediaType mediaType,
                                  Class<? extends HttpMessageConverter<?>> aClass,
                                  ServerHttpRequest serverHttpRequest,
                                  ServerHttpResponse serverHttpResponse) {

        // 定义最终的返回对象
        ApiResponse<Object> response = new ApiResponse<>(StatusCode.SUCCESS);

        if (null == o) {
            return response;
        } else if (o instanceof ApiResponse) {
            response = (ApiResponse<Object>) o;
        } else {
            response.setData(o);
        }

        converter.write(response, MediaType.APPLICATION_JSON, serverHttpResponse);

        return null;
    }
}
